import java.util.*;
/**
 *  Class for an individual sequence.
 *  
 *  On initialization, pir_sequencer will pass a string 
 *  (from the sequence file) that will be parsed here into
 *  a sequence of inputs and a sequence of outputs. 
 *  Upon the end of a sensor input, the sequencer recieves the
 *  sensor number, and passes that to all of the sequences.
 *  
 *  Sequence classes are threaded, and lie in wait until 
 *  interrupted. Upon interrupt, they fire their sequence. 
 * 
 * 
 * @see pir_sequencer
 * @author Sam Reese
 *
 */
public class sequence extends Thread{
	 private final int MAXSEQ = 6;
	 private final int MAXOUTA = 32;
	// private final int MAXOUTB = 32;
	 private int effects;
	 private String sequence;
	 private int at;
	 private int goal;
	 public int curstart;
	 private int[] input_sequence;
	 private String[] output_sequence; 
	 private volatile  boolean GO = false; 
	 private pir_io pir_io_ref;
	 private int time_tick;
	 
	 /**
	  * Constructor summary
	  * 
	  * inputline is expecting something of the form n,n,n,n:n,n,n,n,
	  * which means touch n four times (or actually, trigger off
	  * n that number of times, and it creates a lot of fire
	  * in a particular way. 
	  * 
	  * 
	  * @param inputline String of text forming the sequence
	  */
	  public sequence(String inputline, pir_io pir_io_ref_passed){
		  pir_io_ref = pir_io_ref_passed;
		  input_sequence = new int[MAXSEQ];
		  output_sequence = new String[MAXOUTA];
		  String[] segments = inputline.split(":");
		  if (segments.length > 1){
		     
		  	  sequence = segments[0];
		  	 // output_sequence = Integer.parseInt(segments[1]);
		  	  StringTokenizer st = new StringTokenizer(segments[0], ",");
		  	  int i = -1; //janketyjankshit watch this for obo errors. 
		  	  while (st.hasMoreTokens()){
		  		 input_sequence[++i]=Integer.parseInt(st.nextToken());  
		  	  }
		  	  
		  	   // does not yet parse outputs properly. 
		  	  st = new StringTokenizer(segments[1], ",");
		  	  i = -1; //janketyjankshit watch this for obo errors. 
		  	  while (st.hasMoreTokens()){
		  		 output_sequence[++i] = st.nextToken();  
		  	  } 
		  	  goal = i;
		  	  at = 0;
		  	  curstart = 0;
		  	  goal = sequence.length();
		  	  
		  }else{
			  sequence= new String("0");

		  }
		  time_tick = 500; 
	  }
	  
	  /**
	   *  reset time unit. 
	   * @param t new time tick in ms
	   */
	 public void set_tick(int t){
		 time_tick = t;
	 }
	  
	 /**
	  * set the go value to true, so 
	  * calling interrupt causes the sequence to be triggered.
	  */
	  public void arm(){
		  
		  GO = true;
	  }
	  
	  /**
	   * activate the sequence;
	   */
	  public void go(){
		  int at = 0; 
		  while(at < goal){
			  StringTokenizer parseme = new StringTokenizer(output_sequence[at], ".");
			  while(parseme.hasMoreTokens()){
				  try{ 
				   int curEffect = Integer.parseInt(parseme.nextToken());
				   curEffect =  ((curEffect + effects - curstart) % effects) + 1;
				   pir_io_ref.fire(curEffect , pir_io_ref.PIR_HIGH_ON);
				  }catch(Exception e){
					  System.out.println("Number format exception parsing sequence..." + e);
				  }
			  }
			  try{
			   Thread.sleep(time_tick);
			  } catch (Exception e){
				  System.out.println ("Interrupted during sequence execution, dropped, sequence hickup" );
			  }
			  pir_io_ref.reset();
			  at++;
		  }
		  
	  }
	  
	  public int input(int current_sensor){
		 
		  if (at == 0){
			  curstart = current_sensor;
			  at = 1;
			  return 0;
		  }else {
			 System.out.println("Current = " + current_sensor + " at " + at); 
			  int math;
			  math = ((current_sensor + effects - curstart) % pir_io_ref.effects) + 1;
			  if (input_sequence[at] == math){
				  at++;
				  if (at >= goal){
					  GO = true;
					  return 1;
				  }else{
					  return 0;
				  }
			  }
			  else {
				  at = 0;
			  }
		  }
		 return 0;
	  }
	  
	  
	  /**
	   * This is the main running function of thread.
	   * 
	   * Here, it checks if GO is true, if not, it sleeps
	   * for a long while. momentarially wakes up. The thing
	   * should be triggered by setting go to true (as a 
	   * successful match will), then calling interrupt()
	   * to this thread.
	   */
	  public void run(){
		  if(pir_io.DEBUG){
			  System.out.println("Starting Sequence: ");
		  }
		  if (GO){
			  go();
		  }else{
			  try{
				  Thread.sleep(100000); // or this.wait();
			  }catch(InterruptedException e){
				  if(GO){
					  go();
				  }else {
					  System.out.println("unknown interrupt on Sequence" + e);
				  }
					  
			  }
		  }
		  
	  }
	
}
